package cn.znzz.cjm.config;

import cn.znzz.cjm.authen.MyAuthenticationFalseHandler;
import cn.znzz.cjm.authen.MyAuthenticationSuccessHandler;
import cn.znzz.cjm.author.MyAccessDeniedHandler;
import cn.znzz.cjm.domain.Permission;
import cn.znzz.cjm.filter.SmsCodeFilter;
import cn.znzz.cjm.mapper.PermissionMapper;
import cn.znzz.cjm.mydetail.MyUserDetailsService;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.Configuration;
import org.springframework.http.HttpMethod;
import org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.annotation.web.configurers.ExpressionUrlAuthorizationConfigurer;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;
import org.springframework.security.crypto.password.NoOpPasswordEncoder;
import org.springframework.security.crypto.password.PasswordEncoder;
import org.springframework.security.web.authentication.UsernamePasswordAuthenticationFilter;
import org.springframework.security.web.authentication.rememberme.JdbcTokenRepositoryImpl;
import org.springframework.security.web.authentication.rememberme.PersistentTokenRepository;

import javax.sql.DataSource;
import java.util.List;

@Configuration
@EnableWebSecurity  //开启安全配置
@EnableGlobalMethodSecurity(prePostEnabled = true) //开启方法注解授权
public class WebSecurityConfig extends WebSecurityConfigurerAdapter {
    @Autowired
    private DataSource dataSource;
    //配置记住我的 token存储
    @Bean
    public PersistentTokenRepository tokenStore(){
        JdbcTokenRepositoryImpl repository = new JdbcTokenRepositoryImpl();
        //设置连接池
        repository.setDataSource(dataSource);
        //项目启动时候 如果数据库没有表会创建token存储的表
        //但是如果有就会报错 因为不可能存在两张同名的表
        //repository.setCreateTableOnStartup(true);
        return repository;
    }
    /* @Override
     @Bean
     protected UserDetailsService userDetailsService() {
         //模拟数据  创建User
         User user = new User("admin", "1", new ArrayList<>());
         //完成用户的认证
         InMemoryUserDetailsManager ususerdetails = new InMemoryUserDetailsManager(user);
         return ususerdetails;
     }*/
    @Bean
    public PasswordEncoder getEncoder() {
        // return NoOpPasswordEncoder.getInstance();
        return new BCryptPasswordEncoder();
    }

    /*@Autowired
    private PermissionMapper permissionMapper;
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        //查询系统所有的权限
        List<Permission> list = permissionMapper.selectList(null);

        //配置http安全配置 放行等等
        ExpressionUrlAuthorizationConfigurer<HttpSecurity>.ExpressionInterceptUrlRegistry expressionInterceptUrlRegistry = http.authorizeRequests();//所有请求都要权限
        list.stream().forEach(permission -> {
            expressionInterceptUrlRegistry.antMatchers(permission.getResource()).hasAuthority(permission.getSn());
        });

        expressionInterceptUrlRegistry.antMatchers("/login").permitAll()  //login url 放行
                .antMatchers("/login.html").permitAll() //自定义登录页面放行
                .anyRequest().authenticated()  //其他请求都要认证之后才能访问
                .and().formLogin()  //允许表单提交
                // .successForwardUrl("/test/success")  //认证成功之后的跳转路径
                .successHandler(new MyAuthenSuccessHandler())
                .failureHandler(new MyAuthenFailHanlder())
                .loginPage("/login.html").loginProcessingUrl("/login")
                .and().logout().permitAll()  //退出放行
                .and().csrf().disable();//关闭跨站
    }*/
    @Autowired
    private MyUserDetailsService userDetailsService;
    @Autowired
    private SmsAuthConfig smsAuthConfig;
    @Override
    protected void configure(HttpSecurity http) throws Exception {


        //配置http安全配置 放行等等
        http.authorizeRequests()//所有请求都要权限
                .antMatchers(HttpMethod.POST,"/login","/sms/send/*","/smslogin").permitAll()  //login url 放行
                .antMatchers("/login.html").permitAll() //自定义登录页面放行
                .anyRequest().authenticated()  //其他请求都要认证之后才能访问
                .and().formLogin()  //允许表单提交
                // .successForwardUrl("/test/success")  //认证成功之后的跳转路径
                .successHandler(new MyAuthenticationSuccessHandler())
                .failureHandler(new MyAuthenticationFalseHandler())
                .loginPage("/login.html").loginProcessingUrl("/login")
                .and().logout().permitAll()  //退出放行
                .and().csrf().disable();//关闭跨站
        //授权异常处理
        http.exceptionHandling().accessDeniedHandler(new MyAccessDeniedHandler());
        //配置rememberme
        http.rememberMe()
                .tokenRepository(tokenStore())  //设置token存储方案
                .tokenValiditySeconds(3600)  //设置token的过期时间
                .userDetailsService(userDetailsService) ; //为哪个用户产生token
        //配置短信验证码校验的filter
        //验证码检查的filter
        SmsCodeFilter smsCodeCheckFilter = new SmsCodeFilter();
        //添加验证码检查的filter
        http.addFilterBefore(smsCodeCheckFilter,UsernamePasswordAuthenticationFilter.class);
        http.apply(smsAuthConfig);
    }
}